package com.ccb.sc.payment.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ccb.sc.constant.OrderConstant;
import com.ccb.sc.order.service.IAppOrderService;
import com.ccb.sc.payment.plugin.AbstractPaymentPlugin;
import com.ccb.sc.payment.service.IPaymentPluginService;
import com.ccb.sc.payment.service.IPaymentService;
import com.ccb.sc.payment.vo.PaymentResultVo;
////psl import com.ccb.sc.common.bind.exception.BizException;
import com.ccb.sc.common.code.BizCodeFace;
import com.ccb.sc.common.code.ErrorCode;
import com.ccb.sc.common.modules.common.service.IRedisService;
import com.ccb.sc.common.modules.member.entity.Member;
import com.ccb.sc.common.modules.member.entity.UserThirdAuth;
import com.ccb.sc.common.modules.member.enums.LoginType;
import com.ccb.sc.common.modules.member.service.MemberPointsService;
import com.ccb.sc.common.modules.member.service.MemberService;
import com.ccb.sc.common.modules.member.service.UserThirdAuthService;
import com.ccb.sc.common.modules.order.entity.Order;
import com.ccb.sc.common.modules.payment.entity.Payment;
import com.ccb.sc.common.modules.payment.enums.OrderType;
import com.ccb.sc.common.modules.payment.enums.PaymentMethod;
import com.ccb.sc.common.modules.payment.enums.PaymentStatus;
import com.ccb.sc.common.modules.payment.mapper.PaymentMapper;
import com.ccb.sc.common.modules.shopkeeper.entity.Shopkeeper;
import com.ccb.sc.common.modules.shopkeeper.service.ShopkeeperPointsLogService;
import com.ccb.sc.common.modules.shopkeeper.service.ShopkeeperService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * <p>
 * 支付流水表 服务实现类
 * </p>
 *
 * @author ken
 * @since 2020-09-21
 */
@Service
public class PaymentServiceImpl extends ServiceImpl<PaymentMapper, Payment> implements IPaymentService {

    private static final Logger logger = LoggerFactory.getLogger(PaymentServiceImpl.class);

    @Autowired
    private IPaymentPluginService pluginService;

    @Autowired
    private IAppOrderService orderService;

    @Autowired
    private IRedisService redisService;

    @Autowired
    private MemberService memberService;

    @Autowired
    private MemberPointsService memberPointsService;

    @Autowired
    private ShopkeeperPointsLogService shopkeeperPointsLogService;

    @Autowired
    private ShopkeeperService shopkeeperService;

    @Autowired
    private UserThirdAuthService userThirdAuthService;

    @Override
    public PaymentResultVo submit(Long memberId, String orderId, Integer orderType, String paymentPluginId, HttpServletRequest request) {
        Assert.isTrue(StringUtils.hasText(orderId), "订单号为空");
        AbstractPaymentPlugin paymentPlugin = pluginService.getPaymentPlugin(paymentPluginId);
        Assert.isTrue(paymentPlugin != null &&
                (paymentPlugin.getIsEnabled() || "walletPayPlugin".equals(paymentPluginId)), "支付插件不可用");

        OrderType type = OrderType.getByValue(orderType);
        Assert.notNull(type, "orderType参数错误");

        Payment payment = new Payment();

        Order order = this.orderService.getById(orderId);
        Assert.isTrue(order != null && order.getMemberId().equals(memberId), "未找到订单");
        Assert.isTrue(!order.isExpired(), "订单已过期");
        //Assert.isTrue(order.getStatus().equals(OrderStatus.WAIT_PAY) && order.getPaymentStatus().equals(PaymentStatus.WAIT), "订单状态异常");
        //支付订单金额必须大于0
        if (!Objects.equals(paymentPluginId, "walletPayPlugin")) {
            Assert.isTrue(order.getRealAmount().add(order.getWalletDeductAmount()).compareTo(BigDecimal.ZERO) > 0, "支付订单金额必须大于0");
        }

        BigDecimal amount = paymentPlugin.calculateAmount(order.getRealAmount());

        String paymentId = this.redisService.getNextStandardCodeByDayClean(OrderConstant.PAY_KEY, 7);
        payment.setId(paymentId);
        payment.setAmount(amount);
        payment.setExpire(paymentPlugin.getTimeout() != null ? LocalDateTime.now().plusMinutes(paymentPlugin.getTimeout()) : null);
        payment.setMemo(type.getDesc() + "支付");
        payment.setMethod(PaymentMethod.ONLINE);
        payment.setOrderId(orderId);
        payment.setPaymentMethod(paymentPlugin.getPaymentName());
        payment.setPaymentPluginId(paymentPluginId);
        payment.setStatus(PaymentStatus.WAIT);
        payment.setMemberId(memberId);
        payment.setOrderType(type);
        this.save(payment);
        UserThirdAuth userThirdAuth = this.userThirdAuthService.findByMemberIdAndLoginType(memberId, LoginType.WX_MA);
        /*if(tokenModel.getSourceType() == OrderSourceType.WX_MP){
            request.setAttribute(MpConst.REQUEST_OPENID_KEY, tokenModel.getAttribute(MpConst.SESSION_KEY));
        }*/
        Assert.notNull(userThirdAuth, "授权数据异常！");
        request.setAttribute(AbstractPaymentPlugin.REQUEST_OPENID_KEY, userThirdAuth.getOauthId());
        return paymentPlugin.sendPayRequest(payment.getId(), request);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleWalletPay(Payment payment, Long memberId) {
        // 钱包扣款
        logger.info("开始处理积分支付回调，流水号[[{}]]", payment.getId());
        String orderId = payment.getOrderId();
        // 订单处理
        Order order = this.orderService.getById(orderId);
        // 修改阳光值使用金额
        Member member = this.memberService.getById(memberId);
        if (order.getUsePoints().compareTo(BigDecimal.ZERO) <= 0 && order.getWalletDeductAmount().compareTo(BigDecimal.ZERO) <= 0) {
            //psl //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("支付积分或余额需大于0"));
        }
        // 如果没有扣除记录
        Shopkeeper shopkeeper = this.shopkeeperService.findByMemberId(memberId);
        if (!this.memberPointsService.countByAssociate(memberId, orderId) && !this.shopkeeperPointsLogService.countByAssociate(shopkeeper.getId(), orderId)) {
           //psl //psl throw new BizException(BizCodeFace.createBizCode(ErrorCode.DATE_NULL).message("交易异常"));
        }
        this.handle(payment);
        logger.info("处理余额支付回调结束");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handle(Payment payment) {
        logger.debug("开始处理支付回调，流水号[[{}]]", payment.getId());
        Payment pay = this.payment(payment);
        if (pay == null) {
            return;
        }

        // 订单处理
        this.orderService.payment(pay);

        logger.debug("处理支付回调结束");
    }

    @Override
    public Payment payment(Payment payment) {
        String tradeNo = payment.getTradeNo();
        String payer = payment.getPayer();
        Payment pay = this.getById(payment.getId());

        // 如果已支付过，可能是多余的，忽略
        if (payment.getStatus() != PaymentStatus.WAIT) {
            return null;
        }
        pay.setTradeNo(tradeNo);
        pay.setStatus(PaymentStatus.SUCCESS);
        pay.setPayTime(LocalDateTime.now());
        pay.setPayer(payer);
        pay.setExpire(null);
        this.updateById(pay);

        return pay;
    }


    @Override
    public Payment getByOrderId(String orderId) {
        return this.getOne(new QueryWrapper<Payment>().lambda()
                .eq(Payment::getOrderId, orderId)
                .eq(Payment::getStatus, PaymentStatus.SUCCESS)
                .orderByDesc(Payment::getCreateTime).last("limit 1"));
    }
}
